package com.ruoyi.websocket;

import com.ruoyi.socket.config.BinanceProxyConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 系统代理管理器
 * 基于币安官方推荐和业界最佳实践优化的代理认证实现
 */
@Component
@Slf4j
public class SystemProxyManager {
    
    @Resource
    private BinanceProxyConfig binanceProxyConfig;
    
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private volatile boolean proxyEnabled = false;
    private volatile boolean taskStarted = false;
    private volatile ProxyAuthenticator currentAuthenticator = null;
    
    /**
     * 自定义代理认证器
     * 支持多种认证场景和动态用户名更新
     */
    private class ProxyAuthenticator extends Authenticator {
        private final BinanceProxyConfig config;
        
        public ProxyAuthenticator(BinanceProxyConfig config) {
            this.config = config;
        }
        
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            // 只为代理认证提供凭据
            if (getRequestorType() == RequestorType.PROXY) {
                String currentUser = config.getCurrentUsername();
                String currentPassword = config.getPassword();
                
                log.debug("代理认证请求 - 主机: {}, 端口: {}, 用户: {}, 协议: {}", 
                        getRequestingHost(), getRequestingPort(), currentUser, getRequestingProtocol());
                
                if (currentUser != null && currentPassword != null) {
                    return new PasswordAuthentication(currentUser, currentPassword.toCharArray());
                }
            }
            return null;
        }
    }
    
    /**
     * 启用系统代理
     */
    public void enableSystemProxy() {
        if (!binanceProxyConfig.isEnabled() || !binanceProxyConfig.isValidConfig()) {
            log.warn("代理配置无效，无法启用系统代理");
            return;
        }
        
        try {
            // 关键：解决Java 8u111+的Basic认证禁用问题
            // 参考：https://confluence.atlassian.com/kb/basic-authentication-fails-for-outgoing-proxy-in-java-8u111-909643110.html
            System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
            log.info("已启用Java代理Basic认证支持");
            
            // 设置HTTP代理
            System.setProperty("http.proxyHost", binanceProxyConfig.getHost());
            System.setProperty("http.proxyPort", String.valueOf(binanceProxyConfig.getPort()));
            
            // 设置HTTPS代理
            System.setProperty("https.proxyHost", binanceProxyConfig.getHost());
            System.setProperty("https.proxyPort", String.valueOf(binanceProxyConfig.getPort()));
            
            // 设置SOCKS代理（作为备用）
            System.setProperty("socksProxyHost", binanceProxyConfig.getHost());
            System.setProperty("socksProxyPort", String.valueOf(binanceProxyConfig.getPort()));
            
            // 设置代理认证（如果配置了用户名和密码）
            if (binanceProxyConfig.getUsernameTemplate() != null && binanceProxyConfig.getPassword() != null) {
                String currentUsername = binanceProxyConfig.getCurrentUsername();
                String password = binanceProxyConfig.getPassword();
                
                // 设置系统属性（某些库需要）
                System.setProperty("http.proxyUser", currentUsername);
                System.setProperty("http.proxyPassword", password);
                System.setProperty("https.proxyUser", currentUsername);
                System.setProperty("https.proxyPassword", password);
                System.setProperty("java.net.socks.username", currentUsername);
                System.setProperty("java.net.socks.password", password);
                
                // 关键：设置全局Authenticator来处理代理认证
                // 这是java-websocket库和其他HTTP客户端需要的
                currentAuthenticator = new ProxyAuthenticator(binanceProxyConfig);
                Authenticator.setDefault(currentAuthenticator);
                
                log.info("已设置系统代理认证 - 用户: {}, 代理: {}:{}", 
                        currentUsername, binanceProxyConfig.getHost(), binanceProxyConfig.getPort());
            } else {
                log.info("已设置系统代理（无认证） - 代理: {}:{}", 
                        binanceProxyConfig.getHost(), binanceProxyConfig.getPort());
            }
            
            // 额外设置：针对WebSocket的特殊配置
            System.setProperty("java.net.useSystemProxies", "false"); // 使用我们的显式配置
            
            proxyEnabled = true;
            
            // 启动定时刷新任务
            if (!taskStarted) {
                startProxyRefreshTask();
                taskStarted = true;
            }
            
            log.info("系统代理已启用，当前配置: {}", getCurrentProxyInfo());
            
        } catch (Exception e) {
            log.error("启用系统代理失败", e);
            proxyEnabled = false;
        }
    }
    
    /**
     * 禁用系统代理
     */
    public void disableSystemProxy() {
        try {
            // 清除HTTP代理
            System.clearProperty("http.proxyHost");
            System.clearProperty("http.proxyPort");
            System.clearProperty("http.proxyUser");
            System.clearProperty("http.proxyPassword");
            
            // 清除HTTPS代理
            System.clearProperty("https.proxyHost");
            System.clearProperty("https.proxyPort");
            System.clearProperty("https.proxyUser");
            System.clearProperty("https.proxyPassword");
            
            // 清除SOCKS代理
            System.clearProperty("socksProxyHost");
            System.clearProperty("socksProxyPort");
            System.clearProperty("java.net.socks.username");
            System.clearProperty("java.net.socks.password");
            
            // 清除Java 8u111+的特殊设置
            System.clearProperty("jdk.http.auth.tunneling.disabledSchemes");
            
            // 重置Authenticator为默认值
            Authenticator.setDefault(null);
            currentAuthenticator = null;
            
            proxyEnabled = false;
            
            log.info("系统代理已禁用");
            
        } catch (Exception e) {
            log.error("禁用系统代理失败", e);
        }
    }
    
    /**
     * 刷新代理配置
     */
    public void refreshProxyConfig() {
        if (!proxyEnabled) {
            return;
        }
        
        try {
            // 检查随机数是否过期
            if (binanceProxyConfig.isRandomExpired()) {
                log.info("代理随机数已过期，正在刷新...");
                binanceProxyConfig.generateNewRandom();
                
                // 重新设置代理认证
                if (binanceProxyConfig.getUsernameTemplate() != null && binanceProxyConfig.getPassword() != null) {
                    String newUsername = binanceProxyConfig.getCurrentUsername();
                    
                    System.setProperty("http.proxyUser", newUsername);
                    System.setProperty("https.proxyUser", newUsername);
                    System.setProperty("java.net.socks.username", newUsername);
                    
                    // 重新设置Authenticator
                    currentAuthenticator = new ProxyAuthenticator(binanceProxyConfig);
                    Authenticator.setDefault(currentAuthenticator);
                    
                    log.info("系统代理认证已刷新 - 新用户名: {}", newUsername);
                }
            }
        } catch (Exception e) {
            log.error("刷新代理配置失败", e);
        }
    }
    
    /**
     * 强制刷新代理配置
     */
    public void forceRefreshProxyConfig() {
        if (!proxyEnabled) {
            log.warn("代理未启用，无法强制刷新");
            return;
        }
        
        try {
            log.info("强制刷新代理配置...");
            binanceProxyConfig.generateNewRandom();
            
            // 重新设置代理认证
            if (binanceProxyConfig.getUsernameTemplate() != null && binanceProxyConfig.getPassword() != null) {
                String newUsername = binanceProxyConfig.getCurrentUsername();
                
                System.setProperty("http.proxyUser", newUsername);
                System.setProperty("https.proxyUser", newUsername);
                System.setProperty("java.net.socks.username", newUsername);
                
                // 重新设置Authenticator
                currentAuthenticator = new ProxyAuthenticator(binanceProxyConfig);
                Authenticator.setDefault(currentAuthenticator);
                
                log.info("系统代理认证已强制刷新 - 新用户名: {}", newUsername);
            }
        } catch (Exception e) {
            log.error("强制刷新代理配置失败", e);
        }
    }
    
    /**
     * 启动代理刷新任务
     */
    private void startProxyRefreshTask() {
        scheduler.scheduleAtFixedRate(() -> {
            try {
                refreshProxyConfig();
            } catch (Exception e) {
                log.error("定时刷新代理配置失败", e);
            }
        }, 1, 1, TimeUnit.MINUTES);
        
        log.info("代理刷新定时任务已启动，每分钟检查一次");
    }
    
    /**
     * 获取当前代理信息
     */
    public String getCurrentProxyInfo() {
        if (!proxyEnabled) {
            return "系统代理未启用";
        }
        
        return String.format("HTTP代理: %s:%s, HTTPS代理: %s:%s, 认证用户: %s, Basic认证: %s",
                System.getProperty("http.proxyHost", "未设置"),
                System.getProperty("http.proxyPort", "未设置"),
                System.getProperty("https.proxyHost", "未设置"),
                System.getProperty("https.proxyPort", "未设置"),
                System.getProperty("http.proxyUser", "未设置"),
                System.getProperty("jdk.http.auth.tunneling.disabledSchemes", "默认") != null ? "启用" : "禁用");
    }
    
    /**
     * 检查代理是否启用
     */
    public boolean isProxyEnabled() {
        return proxyEnabled;
    }
    
    /**
     * 测试代理连接
     * 使用币安API进行实际连接测试
     */
    public boolean testProxyConnection() {
        try {
            // 检查系统属性是否正确设置
            String proxyHost = System.getProperty("https.proxyHost");
            String proxyPort = System.getProperty("https.proxyPort");
            
            if (proxyHost == null || proxyPort == null) {
                log.warn("代理系统属性未设置");
                return false;
            }
            
            log.info("代理系统属性设置正确: {}:{}", proxyHost, proxyPort);
            
            // 尝试连接到币安API进行测试
            try {
                URL url = new URL("https://api.binance.com/api/v3/ping");
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(10000);
                connection.setReadTimeout(10000);
                connection.setRequestMethod("GET");
                
                int responseCode = connection.getResponseCode();
                log.info("币安API代理连接测试响应码: {}", responseCode);
                
                boolean success = responseCode == 200;
                if (success) {
                    log.info("代理连接测试成功 - 可以正常访问币安API");
                } else {
                    log.warn("代理连接测试失败 - 响应码: {}", responseCode);
                }
                
                return success;
            } catch (Exception e) {
                log.warn("代理连接测试失败: {}", e.getMessage());
                return false;
            }
            
        } catch (Exception e) {
            log.error("测试代理连接失败", e);
            return false;
        }
    }
    
    /**
     * 获取WebSocket状态信息
     */
    public String getWebSocketStatus() {
        try {
            // 从WebSocketRunner获取状态
            return String.format("代理状态: %s, 系统代理配置: %s, Authenticator: %s", 
                    isProxyEnabled() ? "启用" : "禁用",
                    getCurrentProxyInfo(),
                    currentAuthenticator != null ? "已设置" : "未设置");
        } catch (Exception e) {
            log.error("获取WebSocket状态失败", e);
            return "获取状态失败: " + e.getMessage();
        }
    }
} 